package com.snake.springboot.custom.service.impl.bill;

import com.github.pagehelper.Page;
import com.snake.springboot.custom.api.model.base.CallbackModel;
import com.snake.springboot.custom.api.model.bill.BillEnum;
import com.snake.springboot.custom.api.model.bill.BillPlaceOrderModel;
import com.snake.springboot.custom.api.model.common.CommonVal;
import com.snake.springboot.custom.api.model.pay.PayActModel;
import com.snake.springboot.custom.api.model.pay.PayActRetModel;
import com.snake.springboot.custom.api.request.bill.*;
import com.snake.springboot.custom.api.request.page.PageQuery;
import com.snake.springboot.custom.api.response.bill.BillGoPayRsp;
import com.snake.springboot.custom.api.response.bill.BillRsp;
import com.snake.springboot.custom.api.service.bill.BillService;
import com.snake.springboot.custom.dao.mybatis.entity.bill.BillDO;
import com.snake.springboot.custom.dao.mybatis.mappers.bill.BillMapper;
import com.snake.springboot.custom.service.assemble.bill.BillAssemble;
import com.snake.springboot.custom.service.port.adapter.event.BillRetEvent;
import com.snake.springboot.custom.service.port.adapter.event.BillUccCallbackEvent;
import com.snake.springboot.custom.service.port.adapter.event.PayPlatEvent;
import com.snake.springboot.custom.service.port.adapter.event.PayPlatRetEvent;
import com.snake.springboot.custom.service.utils.PageUtils;
import org.snake.common.exception.OperationException;
import org.snake.common.result.ReturnList;
import org.snake.common.utils.ListUtils;
import org.snake.common.utils.PropertyUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;

@Service
public class BillServiceImpl implements BillService {
    @Autowired
    private BillMapper billMapper;
    @Autowired
    private ApplicationContext applicationContext;

    @Override
    public BillRsp placeOrder(BillPlaceOrderModel data) {
        BillDO billDO = BillAssemble.toBillDO(data);
        billMapper.insertSelective(billDO);
        BillRsp billRsp = BillAssemble.toBillRsp(data);
        return billRsp;
    }


    @Override
    public BillGoPayRsp goPay(BilGoPayModel model) {
        BillDO billDO = billMapper.queryById(model.getBillId());
        if (!billDO.getOrderState().equals(BillEnum.OrderStatus.WAIT.getCode())){
            throw new OperationException("订单状态不可操作");
        }
        BillGoPayRsp billGoPayRsp = new BillGoPayRsp();
        billGoPayRsp.setBillId(model.getBillId());
        //支付金额为零，则不需要去支付
        if (BigDecimal.ZERO.compareTo(billDO.getPayAmount())==0){
            billDO.setPayState(CommonVal.Y);
            billDO.setOrderState(BillEnum.OrderStatus.FINISHED.getCode());
            billDO.setPayAccType(model.getPayAccType());
            billDO.setPayId("0");
            billMapper.updatePay(billDO);
            //执行完成的业务
            applicationContext.publishEvent(new BillUccCallbackEvent(this,billDO));
            billGoPayRsp.setIsPay(CommonVal.Y);
            return billGoPayRsp;
        }
        //去支付
        PayActModel actModel = BillAssemble.toPayModel(billDO,model);
        PayPlatEvent event = new PayPlatEvent(this, actModel);
        applicationContext.publishEvent(event);

        billGoPayRsp.setPayMsgModel(event.getResult());
        billGoPayRsp.setIsPay(CommonVal.N);
        return billGoPayRsp;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void callback(CallbackModel model) {
        //回调
        BillDO billDO = billMapper.queryById(model.getPayCode());
        if (!billDO.getPayState().equals(CommonVal.N)){
            return;
        }
        billDO.setPayState(CommonVal.Y);
        billDO.setOrderState(BillEnum.OrderStatus.FINISHED.getCode());
        billDO.setPayAccType(model.getPayAccType());
        billDO.setPayId(model.getPayId());
        billMapper.updatePay(billDO);
        //执行完成的业务
        applicationContext.publishEvent(new BillUccCallbackEvent(this,billDO));
    }

    @Override
    public ReturnList<BillRsp> custQueryBillList(PageQuery<BillQuery> params) {
        return adminQueryBillList(params);
    }

    @Override
    public ReturnList<BillRsp> adminQueryBillList(PageQuery<BillQuery> params) {
        Page<Object> objects = PageUtils.forcePage(params.getPage());
        BillDO billDO = BillAssemble.toBillDO(params.getParams());
        List<BillDO> list = billMapper.queryBillList(billDO);
        List<BillRsp> rspList = ListUtils.copy(list, BillRsp.class);
        return new ReturnList<>(rspList,objects.getTotal());
    }

    @Override
    public void goClose(BilGoPayModel model) {
        BillDO billDO = billMapper.queryById(model.getBillId());
        if (!billDO.getOrderState().equals(BillEnum.OrderStatus.WAIT.getCode())){
            throw new OperationException("订单状态不可操作");
        }
        billDO.setOrderState(BillEnum.OrderStatus.CLOSED.getCode());
        billMapper.updateClose(billDO);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void remove(String billId) {
        billMapper.remove(billId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void goRet(BillGoRetModel model) {
        BillDO billDO = billMapper.queryById(model.getBillId());
        if (billDO.getPayState().equals(CommonVal.N)||billDO.getRetState().equals(CommonVal.Y)){
            throw new OperationException("订单状态不可操作");
        }
        //调起支付模型
        PayActRetModel actModel = BillAssemble.actRetModelAss(billDO,model);
        billMapper.updateRet(billDO);
        if (BigDecimal.ZERO.compareTo(billDO.getPayAmount())!=0){
            PayPlatRetEvent platRetEvent = new PayPlatRetEvent(this, actModel);
            applicationContext.publishEvent(platRetEvent);
        }
        //退策略
        BillRetEvent retEvent = new BillRetEvent(this, billDO);
        applicationContext.publishEvent(retEvent);
    }

    @Override
    public void billPayedAdd(BillPayedAddModel data) {
        BillDO billDO = new BillDO();
        PropertyUtils.copyProperties(billDO, data);
        billMapper.insertSelective(billDO);
    }

    @Override
    public void billRetEd(BillRetEdModel data) {
        BillDO billDO = new BillDO();
        billDO.setBillId(data.getBillId());
        billDO.setRetAmount(data.getRetAmount());
        billDO.setRetState(CommonVal.Y);
        billMapper.updateRet(billDO);
    }

    @Override
    public BillRsp detail(String billId) {
        BillDO billDO = billMapper.queryById(billId);
        return BillAssemble.toBillRsp(billDO);
    }
}
